<?php

/**
 * 服务器上报数据格式：
 * 
 *     1、LOGIN/:NAME/:SWITCH001
 *     2、CONTROL/:SWITCH001/:OPEN1
 *     3、SHOW/:SHOW001/:11:11
 *     4、REMOTE/:IRREMOTE001/:POWER
 *     5、LUMIN/:HOME/:140.23
 *     6、PERSSURE/:HOME/:1004.12
 *     7、HUMIDITY/:HOME/:37.12
 *     8、RESPONSE/:SWITCH003/:CLOSE1
 *     9、IRTEMP/:IRTEMP001/:43.93
 *
 */
class DeviceController {

	/* 心跳检查时间（s）*/
	const LOGIN_TIME = 99;

	private $redis;

	private $server;

	private $file;

	private $config;

	/**
	 * 构造基础资源
	 */
	public function __construct($server, $file, $config)
	{
		$this->server = $server;
		$this->file = $file;
		$this->config = $config;
		$this->redis = self::linkRedis($config);
	}

	/**
	 * 连接 redis
	 */
	private function linkRedis($c) {
		$redis = new Redis();
		$redis->pconnect($c['REDIS_HOST'], $c['REDIS_PORT']);
		$redis->select($c['REDIS_SELESE']);
		return $redis;
	}

	/**
	 * debug logs
	 */
	private function debugLogs($log) {
		$this->file->writeLogFile("./logs/debug/", $log);
	}

	/**
	 * error logs
	 */
	private function errorLogs($log) {
		$this->file->writeLogFile("./logs/error/", $log);
	}

	/**
	 * warning logs
	 */
	private function warningLogs($log) {
		$this->file->writeLogFile("./logs/warning/", $log);
	}

	/**
	 * 设备登陆
	 */
	private function deviceLogin($data, $fd) {
		$this->redis->set($data, $fd, self::LOGIN_TIME);
		$this->redis->set("DEVICENAME_$fd", $data, self::LOGIN_TIME);
	}

	/**
	 * 维护正常连接 删除僵尸连接
	 */
	private function clientManage($fd)
	{

		if (!$this->redis->sismember("DEVICENAMELIST", $fd)) {
			$this->redis->sadd("DEVICENAMELIST", $fd);
		}

		if (!$this->redis->exists('DELAY') && $this->redis->exists("DEVICENAMELIST")) {
			
			$this->redis->set('DELAY', date("Y-m-d_H:i:s"), self::LOGIN_TIME + 1);
			/*$clientList = $this->server->getClientList(0, 99);
			$device_name_list = $this->redis->smembers("DEVICENAMELIST");

			if (is_array($clientList) && is_array($device_name_list) && 
				count($clientList) && count($device_name_list)) {

				$delList = array_diff($clientList, $device_name_list);

				foreach ($delList as $clientId) {
					$this->server->close($clientId, true);
					self::debugLogs("delete client id = $clientId");
				}

			}*/
			
			$this->redis->del("DEVICENAMELIST");
			
		}
	}

    /**
     * 时间展示
     */
	private function timeShow($name, $data) {
		
		if ($fd = $this->redis->get($name)) {
			$this->server->send($fd, $data);
		}

	}

    /**
     * 开关控制
     */
	private function controlSwitch($name, $code) {
		
		if ($fd = $this->redis->get($name)) {
			self::debugLogs("control device client device = $name id = $fd code = $code");
			if (self::checkStatus($name, $code) && $this->server->send($fd, $code)) {
				self::debugLogs("control device $fd success");
			} else {
				self::debugLogs("control device $fd fail");
			}
		} else {
			self::errorLogs("control device error fd = $fd code = $code");
		}

	}

    /**
     * 红外遥控
     */
	private function remote($name, $code)
	{
		if ($remote_ids = $this->redis->get("$name%$code")) {
			$device_codes = explode(",", $remote_ids);
			foreach ($device_codes as $key => $device_code) {
				$info = explode("/:", $device_code);
				switch (sizeof($info)) {
					case 1:
						$url = $this->config['WEB_HOST']."/api/clockSwitch?id=".$info[0];
						shell_exec("(curl $url > /dev/null 2>&1 &)");
						break;
					case 2:
						self::controlSwitch($info[0], $info[1]);
						break;
					default:
						break;
				}
			}
		}
	}
    
    /**
     * 亮度记录
     */
	private function lumin($name, $light = 0) {
		$this->redis->set("LUMIN%$name", $light, self::LOGIN_TIME);
		$this->redis->hset("LUMINLIST", date('H'), $light);
		$this->redis->expire("LUMINLIST", 86400);
	}

	/**
	 * 温度记录
	 */
	private function temp($name, $temp = 0) {
		$this->redis->set("TEMP%$name", $temp, self::LOGIN_TIME);
		if ($name == "HOME") {
			$this->redis->hset("TEMPLIST", date('H'), $temp);
			$this->redis->expire("TEMPLIST", 86400);
		} else {
			$this->redis->hset("TEMPOUTLIST", date('H'), $temp);
			$this->redis->expire("TEMPOUTLIST", 86400);
		}
		
	}

	/**
	 * 气压记录
	 */
	private function perssure($name, $pers = 0) {
		$this->redis->set("PERSSURE%$name", $pers, self::LOGIN_TIME);
		$this->redis->hset("PERSSURELIST", date('H'), $pers);
		$this->redis->expire("PERSSURELIST", 86400);
	}

	/**
	 * 湿度记录
	 */
	private function humidity($name, $hum = 0) {
		$this->redis->set("HUMIDITY%$name", $hum, self::LOGIN_TIME);
		$this->redis->hset("HUMIDITYLIST", date('H'), $hum);
		$this->redis->expire("HUMIDITYLIST", 86400);
	}

	/**
	 * 红外温度上报
	 */
	private function irtemp($name, $temp = 0) {
		$this->redis->set("IRTEMP%$name", $temp, self::LOGIN_TIME);
		$this->redis->hset("IRTEMPLIST", date('i'), $temp);
		$this->redis->expire("IRTEMPLIST", 86400);
	}

    /**
     * 记录状态
     */
	private function response($name, $code) {

		switch ($code) {
			case 'OPEN':
				$this->redis->hset("RESPONSE%$name", 0, 1);
				break;
			case 'CLOSE':
				$this->redis->hset("RESPONSE%$name", 0, 0);
				break;
			 case 'OPEN1':
				$this->redis->hset("RESPONSE%$name", 0, 1);
				break;
			 case 'CLOSE1':
				$this->redis->hset("RESPONSE%$name", 0, 0);
				break;
			 case 'OPEN2':
				$this->redis->hset("RESPONSE%$name", 1, 1);
				break;
			 case 'CLOSE2':
				$this->redis->hset("RESPONSE%$name", 1, 0);
				break;
			 default:
				$this->redis->set("RESPONSEVALUE%$name", $code, self::LOGIN_TIME);
				break;
		}

		if ($this->redis->exists("RESPONSE%$name")) {
			$this->redis->expire("RESPONSE%$name", self::LOGIN_TIME);
		}
	}

    /**
     * 检查开关状态
     */
    private function checkStatus($name, $code) {
		if ($this->redis->exists("RESPONSE%$name")) {
			switch ($code) {
				case 'OPEN':
					return ($this->redis->hget("RESPONSE%$name", 0)==0);
				case 'CLOSE':
					return ($this->redis->hget("RESPONSE%$name", 0)==1);
				case 'OPEN1':
					return ($this->redis->hget("RESPONSE%$name", 0)==0);
				case 'CLOSE1':
					return ($this->redis->hget("RESPONSE%$name", 0)==1);
				case 'OPEN2':
					return ($this->redis->hget("RESPONSE%$name", 1)==0);
				case 'CLOSE2':
					return ($this->redis->hget("RESPONSE%$name", 1)==1);
				default:
					break;
			}
		}
        return true;
	}

    /**
     * 主方法
     */
    public function control($data, $fd = 0)
    {

         $info = strstr($data, "/:") ? explode("/:", $data) : [];
         $clientName = $this->redis->exists("DEVICENAME_$fd") ? 
						$this->redis->get("DEVICENAME_$fd") : "CLIENT$fd";

         if ((sizeof($info) == 3) && ($type = $info[0])) {
            
			self::clientManage($fd);
			$say = $data;

			switch ($type) {
				case "LOGIN" :
					self::deviceLogin($info[2], $fd);
					break;
				case "CONTROL" :
					self::controlSwitch($info[1], $info[2]);
					break;
				case "SHOW" :
					self::timeShow($info[1], $info[2]);
					break;
				case "REMOTE" :
					self::remote($info[1], $info[2]);
					break;
				case "LUMIN" :
					self::lumin($info[1], $info[2]);
					break;
				case "TEMP" :
					self::temp($info[1], $info[2]);
					break;
				case "PERSSURE" :
					self::perssure($info[1], $info[2]);
					break;
				case "HUMIDITY" :
					self::humidity($info[1], $info[2]);
					break;
				case "RESPONSE" :
					self::response($info[1], $info[2]);
					break;
				case "IRTEMP" :
					self::irtemp($info[1], $info[2]);
					break;
				default:
					break;
			}

		} else {
			self::warningLogs("$clientName warning code is: $data");
			$say = " ??? ! ";
		}

		$datetime = date('H:i:s');
		echo "$clientName $datetime\n $say\n";
		
	}
}